#include <map>
#include <vector>
#include <string>
#include <tr1/memory>
#include <boost/foreach.hpp>
#include <boost/scoped_ptr.hpp>

#include "page.h"
#include "token.h"
#include "page_db.h"

namespace jsearch
{

struct page::Impl
{
	public:
		Impl(int id, std::tr1::shared_ptr<page_db>& db);

		bool calculate_count_max();
		bool calculate_freq();

		int get_count_max(){ return count_max;}
		int id() const { return page_id;}

		bool get_terms();
		std::map<std::string,term_info> terms;

	private:
		int page_id;
		int count_max;
		std::tr1::shared_ptr<page_db> pdb;
};

page::Impl::Impl(int id, std::tr1::shared_ptr<page_db>& db)
	:page_id(id),count_max(0)
{
    pdb = db;

	if (id<0 ||	id>=pdb->size()) {
		std::cerr<<"error:initial ID is not valid."
			<<std::endl;
		exit(1);
	}
}

//member of class term info
term_info::term_info(int c,double f)
:count(c),freq(f)
{
	if (c<0 || f<0.0) {
		std::cerr<<"error:class term_info initial value is invalid"
			<<std::endl;
		exit(1);
	}
}

//************************************************/
//member of class page
//************************************************/
page::page(int id,std::tr1::shared_ptr<page_db>& db)
:pimpl(new Impl(id,db))
{ }

const std::map<std::string,term_info>& page::terms()
{
	return pimpl->terms;
}

int page::get_count_max() const
{ 
	return pimpl->get_count_max();
}

int page::id() const
{ 
	return pimpl->id();
}

bool page::build_page_index()
{
	if (!pimpl->get_terms())
		return false;

	pimpl->calculate_count_max();
	pimpl->calculate_freq();

	return true;
}

bool page::Impl::get_terms()
{
	if (page_id<0 || page_id>=pdb->size()) {
		std::cerr<<"error:page ID is invalid"<<std::endl;
		return false;
	}

	std::string file=pdb->getnamebyid(page_id);
	if (file.empty())
		return false;

	token tk(file);
	std::string s;
	while( (s=tk.next_token()) != "") {
		++terms[s].count;
	}

	return true;
}

bool page::Impl::calculate_count_max()
{
	count_max=0;
	typedef std::map<std::string, term_info>::iterator MSTI;
	MSTI pos= terms.begin();
	MSTI end= terms.end();
	for ( ;pos!=end; ++pos) {
		if (pos->second.count > count_max)
			count_max=pos->second.count;
	}

	return true;
}

bool page::Impl::calculate_freq()
{
	calculate_count_max();
	typedef std::map<std::string, term_info>::iterator MSTI;
	MSTI pos= terms.begin();
	MSTI end= terms.end();

	for ( ; pos!=end; ++pos ) {
		double p = static_cast<double>(pos->second.count);
		double q = static_cast<double>(count_max);
		pos->second.freq = static_cast<double>(p/q);
	}

	return true;
}

}//end namespace
